#include <cstddef>
#include <cstdlib>
#include <cstdio>
#include <wchar.h>
#include <pthread.h>
#include "asan_internal_defs.h"
#include "asan_interceptors.h"
#include "interception.h"

#define ASAN_INTERFACES_MACRO DECLARE_REAL_AND_INTERCEPTOR
#include "asan_interfaces.inc"
#undef ASAN_INTERFACES_MACRO

using namespace __sanitizer;


extern "C" {
void InitializeAsanInterceptors() {
  static bool was_called_once = false;
  ASSERT(!was_called_once, "__sanitizer::InitializeAsanInterceptors was called again");
  was_called_once = true;

  ASAN_INTERCEPT_FUNC(malloc);
  ASAN_INTERCEPT_FUNC(calloc);
  ASAN_INTERCEPT_FUNC(realloc);
  ASAN_INTERCEPT_FUNC(free);
  // ASAN_INTERCEPT_FUNC(alloca);

  ASAN_INTERCEPT_FUNC(memcpy);
  ASAN_INTERCEPT_FUNC(memset);
  ASAN_INTERCEPT_FUNC(memmove);

  // InitializeCommonInterceptors();
  // InitializeSignalInterceptors();

  // Intercept str* functions.
  ASAN_INTERCEPT_FUNC(memcmp);
  ASAN_INTERCEPT_FUNC(strlen);
  ASAN_INTERCEPT_FUNC(strnlen);
  ASAN_INTERCEPT_FUNC(strcat);
  ASAN_INTERCEPT_FUNC(strncat);
  ASAN_INTERCEPT_FUNC(strcpy);
  ASAN_INTERCEPT_FUNC(strncpy);
  ASAN_INTERCEPT_FUNC(strdup);

  ASAN_INTERCEPT_FUNC(wcscpy);
  ASAN_INTERCEPT_FUNC(wcsncpy);

  ASAN_INTERCEPT_FUNC(printf);
  ASAN_INTERCEPT_FUNC(snprintf);

  // To handle several overloaded functions
  const char* (*__asan_strchr_1)(const char *, int) = &strchr;
  ASAN_INTERCEPT_FUNC_WITH_ADDR(strchr, __asan_strchr_1);
  char* (*__asan_strchr_2)(char *, int) = &strchr;
  ASAN_INTERCEPT_FUNC_WITH_ADDR(strchr, __asan_strchr_2);

  const char* (*__asan_strstr_1)(const char *, const char *) = &strstr;
  ASAN_INTERCEPT_FUNC_WITH_ADDR(strstr, __asan_strstr_1);
  char* (*__asan_strstr_2)(char *, const char *) = &strstr;
  ASAN_INTERCEPT_FUNC_WITH_ADDR(strstr, __asan_strstr_2);
  // VReport(1, "AddressSanitizer: libc interceptors initialized\n");
}

}
